"""
认证与权限依赖注入模块（无兼容层，内部项目专用）
"""
from typing import Callable, Awaitable

from fastapi import Depends
from fastapi import Request
from fastapi.security import OAuth2PasswordBearer

from app.common.audit_const import AUDIT_MAP, AuditMeta
from app.common.permissions import SystemPerm, AnalyticsPerm, TelemetryPerm, DevicePerm, FilePerm, ReportPerm
from app.common.security import decode_token
from app.crud.audit_log_crud import create_audit_log_with_body
from app.crud.permission_crud import check_user_permission
from app.crud.user_crud import get_user_by_username
from app.schemas.user_schemas import UserInDB
from common.database import DatabaseService, get_db_dependency
from common.exceptions import BizException, ErrorCode
from common.logger import create_logger
from common.request import safe_extract_body

logger = create_logger(__name__)
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/auth/token")


# ---------------- 当前用户 ----------------
async def get_current_user(
		token: str = Depends(oauth2_scheme),
		db: DatabaseService = Depends(get_db_dependency)
) -> UserInDB:
	"""通过 JWT 获取当前用户（无别名）"""
	if not token or not isinstance(token, str):
		raise BizException.from_error_code(ErrorCode.INVALID_CREDENTIALS, message="令牌格式错误")

	username = decode_token(token)
	user = await get_user_by_username(db, username)
	if not user:
		raise BizException.from_error_code(ErrorCode.USER_NOT_FOUND)
	if user.disabled:
		raise BizException.from_error_code(ErrorCode.USER_DISABLED)
	return user


# ---------------- 权限工厂 ----------------
def check_permission(permission_code: str) -> Callable[..., Awaitable[UserInDB]]:
	"""
	生成指定权限的依赖校验函数；
	使用方：`user: UserInDB = Depends(check_permission(TelemetryPerm.VIEW))`
	"""

	async def _checker(
			current_user: UserInDB = Depends(get_current_user),
			db: DatabaseService = Depends(get_db_dependency)
	) -> UserInDB:
		if not permission_code or not isinstance(permission_code, str):
			raise BizException.from_error_code(ErrorCode.BAD_REQUEST, message="权限编码无效")
		has = await check_user_permission(db, current_user.user_code, permission_code)
		if not has:
			logger.warning("用户[%s]缺少权限[%s]", current_user.user_code, permission_code)
			raise BizException.from_error_code(ErrorCode.FORBIDDEN, message=f"缺少权限: {permission_code}")
		return current_user

	return _checker


# 常用权限依赖
require_user_manage_permission = check_permission(SystemPerm.USER_MANAGE)
require_role_manage_permission = check_permission(SystemPerm.ROLE_MANAGE)
require_permission_manage_permission = check_permission(SystemPerm.PERM_MANAGE)
require_audit_log_view_permission = check_permission(SystemPerm.AUDIT_VIEW)
require_analytics_view = check_permission(AnalyticsPerm.VIEW)
RequireTelemetryView = check_permission(TelemetryPerm.VIEW)
# 权限依赖
require_device_manage = check_permission(DevicePerm.DEVICE_MANAGE)

require_file_manage = check_permission(FilePerm.FILE_MANAGE)

# 报表权限依赖
require_report_view = check_permission(ReportPerm.VIEW)
require_report_export = check_permission(ReportPerm.EXPORT)


# ---------------- 审计日志依赖 ----------------
def audit_log():
	"""
	自动记录操作审计日志；
	使用方：router 里 `audit_id: int = Depends(audit_log())`
	"""

	async def _log(
			request: Request,
			db: DatabaseService = Depends(get_db_dependency),
			current_user: UserInDB = Depends(get_current_user),
	) -> int:
		key = (request.method, request.url.path.split("?")[0])
		meta = AUDIT_MAP.get(key) or AuditMeta(request.method, "API")

		resolved_target_id = request.path_params.get(
			"role_id",
			request.path_params.get("permission_id",
									request.path_params.get("user_id",
															request.path_params.get("user_code", "N/A")))
		)

		body = await safe_extract_body(request)

		audit_id = await create_audit_log_with_body(
			db=db,
			user_code=current_user.user_code,
			action=meta.action,
			target_type=meta.target_type,
			target_id=resolved_target_id,
			request_ip=request.client.host or "unknown",
			request_uri=str(request.url),
			request_body=body,
			result=True,
		)
		request.state.audit_id = audit_id
		return audit_id

	return _log
